package xlog

import (
	"bytes"
	"io"
	"os"
	"runtime/debug"
	"strconv"
	"time"

	"gitee.com/xuesongtao/gotool/base"
	"gitee.com/xuesongtao/gotool/xdebug"
)

const (
	logFilter = "/print.go"
)

// printErr
func (x *XLogger) printErr(std io.Writer, lead string, value ...interface{}) {
	if x.config.PrintErrStack {
		if errMsg := string(debug.Stack()); errMsg != "" {
			value = append(value, "Stack: \n"+errMsg)
		}
	}
	x.print(std, lead, value...)
}

// print 将内容写入目标 io
func (x *XLogger) print(std io.Writer, lead string, value ...interface{}) {
	var (
		now    = time.Now()
		buffer = x.getBuf()
	)
	defer x.putBuf(buffer)

	// 处理时间
	timeFormat := ""
	if x.config.Flags&XLogDate > 0 {
		timeFormat += "2006-01-02 "
	}
	if x.config.Flags&XLogTime > 0 {
		timeFormat += "15:04:05 "
	}
	if x.config.Flags&XLogTimeMill > 0 {
		timeFormat += "15:04:05.000 "
	}
	if timeFormat != "" {
		buffer.WriteString(now.Format(timeFormat))
	}

	// level 部分
	if len(lead) > 0 {
		buffer.WriteString(lead)
		if len(value) > 0 {
			buffer.WriteByte(' ')
		}
	}

	// 判断下是否要打印调用
	if x.config.Flags&FileLong > 0 {
		_, path, line := xdebug.CallerWithFilter(logFilter, x.config.CallSkip)
		buffer.WriteString(path + ":" + strconv.Itoa(line) + ": ")
	}
	if x.config.Flags&FileShort > 0 {
		_, path, line := xdebug.CallerWithFilter(logFilter, x.config.CallSkip)
		buffer.WriteString(xdebug.ParseCallFile(path) + ":" + strconv.Itoa(line) + ": ")
	}

	if len(x.config.Prefix) > 0 {
		buffer.WriteString(x.config.Prefix + " ")
	}

	tempStr := ""
	valueStr := ""
	for _, v := range value {
		if err, ok := v.(error); ok {
			tempStr = err.Error()
		} else {
			tempStr = base.Str(v)
		}

		l := len(valueStr)
		if l > 0 {
			if valueStr[l-1] == '\n' {
				// 删除一个空行/换行符
				if tempStr[0] == '\n' {
					valueStr += tempStr[1:]
				} else {
					valueStr += tempStr
				}
			} else {
				valueStr += " " + tempStr
			}
		} else {
			valueStr = tempStr
		}
	}

	buffer.WriteString(valueStr)
	// fmt.Println("bufStr:", buffer.String())
	buffer.WriteByte('\n')

	x.mu.Lock()
	x.printToWriter(std, now, buffer)
	x.mu.Unlock()
}

// printToWriter 写入
func (x *XLogger) printToWriter(std io.Writer, now time.Time, buffer *bytes.Buffer) {
	if len(x.config.Writer) == 0 {
		// 写入文件
		if x.config.FilePath != "" {
			x.printToFile(now, buffer)
		}

		// 打印到控制台
		if x.config.StdPrint {
			if _, err := std.Write(buffer.Bytes()); err != nil {
				panic(err)
			}
		}
	} else {
		for _, w := range x.config.Writer {
			if _, err := w.Write(buffer.Bytes()); err != nil {
				panic(err)
			}
		}
	}
}

// printToFile 写入文件
func (x *XLogger) printToFile(now time.Time, buffer *bytes.Buffer) {
	logFilePath := x.config.FilePath + now.Format(base.DateFmt) + ".log"

	// 从文件池里取一个, filePool 是带有锁的, 这里能保证多协程串行
	fh, err := filePool.Get(logFilePath, os.O_CREATE|os.O_APPEND|os.O_RDWR)
	if err != nil {
		panic(err)
	}
	// fmt.Printf("filePool: %+v\n", filePool)
	defer filePool.Put(fh)

	if _, err := fh.GetFile().Write(buffer.Bytes()); err != nil {
		panic(err)
	}
}
